﻿using System;
using System.ComponentModel;
using System.Collections;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Collections.Generic;
using System.Linq;

namespace SL8.SL.Data
{
    public class DynamicDataCollectionView : ICollectionView, IPagedCollectionView, INotifyPropertyChanged
    {
        private int _pageSize = 1;

        public event EventHandler<EventArgs> PageChanged;
        public event EventHandler<PageChangingEventArgs> PageChanging;
        public event PropertyChangedEventHandler PropertyChanged;
        public event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged;
        public event EventHandler CurrentChanged;
        public event CurrentChangingEventHandler CurrentChanging;

        private object _currentItem;

        private CultureInfo _culture;
        private Predicate<object> _filter;
        private SortDescriptionCollection _sortDescriptions;

        private ObservableCollection<object> internalSourceCollection = new ObservableCollection<object>();
        private int _currentPosition;
        private CollectionViewFlags _flags;
        private int _pageIndex = -1;
        private IDynamicDataProvider dynamicDataProvider = null;
        private ObservableCollection<GroupDescription> _groupDescriptions;
        private int _itemCount;
        private int _totalItemCount;

        #region ICollectionView
        public bool CanFilter
        {
            get
            {
                return true;
            }
        }

        public bool CanGroup
        {
            get
            {
                return true;
            }
        }

        public bool CanSort
        {
            get
            {
                return true;
            }
        }

        public bool Contains(object item)
        {
            return this.internalSourceCollection.Contains(item);
        }

        public System.Globalization.CultureInfo Culture
        {
            get
            {
                if (this._culture == null)
                {
                    this._culture = new System.Globalization.CultureInfo("zh-Hans");
                }

                return this._culture;
            }

            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }

                if (this._culture != value)
                {
                    this._culture = value;
                    this.RaisePropertyChanged("Culture");
                }
            }
        }

        public object CurrentItem
        {
            get
            {
                return this._currentItem;
            }

            private set
            {
                this._currentItem = value;
                this.RaisePropertyChanged("CurrentItem");
            }
        }

        public int CurrentPosition
        {
            get
            {
                return this._currentPosition;
            }

            private set
            {
                this._currentPosition = value;
                this.RaisePropertyChanged("CurrentPosition");
            }
        }

        public IDisposable DeferRefresh()
        {
            return new DeferHelper(this);
        }

        public Predicate<object> Filter
        {
            get
            {
                return this._filter;
            }
            set
            {
                if (!this.CanFilter)
                {
                    throw new NotSupportedException("不支持过滤");
                }

                if (this._filter != value)
                {
                    this._filter = value;
                    // this.RefreshOrDefer();
                    this.RaisePropertyChanged("Filter");
                }
            }
        }

        public System.Collections.ObjectModel.ObservableCollection<GroupDescription> GroupDescriptions
        {
            get
            {
                if (this._groupDescriptions == null)
                {
                    this._groupDescriptions = new ObservableCollection<GroupDescription>();
                }

                return this._groupDescriptions;
            }
        }

        public System.Collections.ObjectModel.ReadOnlyObservableCollection<object> Groups
        {
            get
            {
                return null;
            }
        }

        public bool IsCurrentAfterLast
        {
            get
            {
                return false;
            }
        }

        public bool IsCurrentBeforeFirst
        {
            get
            {
                return true;
            }
        }

        public bool IsEmpty
        {
            get
            {
                return this.internalSourceCollection == null || this.internalSourceCollection.Count == 0;
            }
        }

        public DynamicDataCollectionView(IDynamicDataProvider provider)
        {
            if (provider == null)
            {
                throw new ArgumentNullException("provider");
            }

            this.dynamicDataProvider = provider;
        }

        public bool MoveCurrentTo(object item)
        {
            return this.MoveCurrentToPosition(this.IndexOf(item));
        }

        public bool MoveCurrentToFirst()
        {
            if (this.IsEmpty)
            {
                return false;
            }
            else
            {
                return this.MoveCurrentTo(0);
            }
        }

        public bool MoveCurrentToLast()
        {
            if (this.IsEmpty)
            {
                return false;
            }
            else
            {
                return this.MoveCurrentTo(this.internalSourceCollection.Count - 1);
            }
        }

        public bool MoveCurrentToNext()
        {
            if (this.IsEmpty)
            {
                return false;
            }
            else
            {
                return this.MoveCurrentTo(this.CurrentPosition + 1);
            }
        }

        public bool MoveCurrentToPosition(int position)
        {
            bool isMove = false;
            if (position < -1)
            {
                isMove = false;
            }
            else if (position == -1)
            {
                isMove = true;
            }
            else
            {
                if (this.IsEmpty)
                {
                    isMove = false;
                }
                else
                {
                    isMove = this.internalSourceCollection.Count > position;
                }
            }

            if (isMove)
            {
                this.SetCurrentToPosition(position);
                this.OnCurrentChanged();
            }

            return isMove;
        }

        public bool MoveCurrentToPrevious()
        {
            throw new NotImplementedException();
        }

        public void Refresh()
        {
            SortDescription[] arrSort = new SortDescription[this.SortDescriptions.Count];
            this.SortDescriptions.CopyTo(arrSort, 0);

            if (this.PageSize > 0 && this.PageIndex == -1)
            {
                this.PageIndex = 0;
            }

            //SearchCondition searchCondition = new SearchCondition(null, arrSort, this.PageIndex, this.PageSize);

            this.dynamicDataProvider.GetDynamicDataRecordCount((tcount) =>
            {
                this.dynamicDataProvider.GetDynamicData(this.PageIndex, this.PageSize, arrSort, (result) =>
                {
                    if (result == null)
                    {
                        this.internalSourceCollection.Clear();
                    }
                    else
                    {
                        if (result.Result == null)
                        {
                            this.internalSourceCollection.Clear();
                        }
                        else
                        {
                            if (result.Error == null)
                            {
                                this.internalSourceCollection.Clear();
                                foreach (var item in result.Result)
                                {
                                    this.internalSourceCollection.Add(item);
                                }

                                this.TotalItemCount = tcount;
                                this.ItemCount = tcount;
                                this.RaisePropertyChanged("PageSize");
                            }
                            else
                            {
                                throw result.Error;
                            }
                        }
                    }

                    this.OnCollectionChanged();
                });
            });
        }

        public SortDescriptionCollection SortDescriptions
        {
            get
            {
                if (this._sortDescriptions == null)
                {
                    this._sortDescriptions = new SortDescriptionCollection();
                }

                return this._sortDescriptions;
            }
        }

        public System.Collections.IEnumerable SourceCollection
        {
            get
            {
                return this.internalSourceCollection;
            }
        }

        public System.Collections.IEnumerator GetEnumerator()
        {
            return this.internalSourceCollection.GetEnumerator();
        }
        #endregion

        #region IPagedCollectionView
        public bool CanChangePage
        {
            get
            {
                return true;
            }
        }

        public bool IsPageChanging
        {
            get
            {
                return true;
            }
        }

        public int ItemCount
        {
            get
            {
                if (this.IsEmpty)
                {
                    return 0;
                }
                else
                {
                    return this._itemCount;
                }
            }

            private set
            {
                this._itemCount = value;
                this.RaisePropertyChanged("ItemCount");
                this.RaisePropertyChanged("PageCount");
                this.RaisePropertyChanged("PageSize");
                this.RaisePropertyChanged("PageIndex");
            }
        }

        public bool MoveToFirstPage()
        {
            return this.MoveToPage(0);
        }

        public bool MoveToLastPage()
        {
            bool a = (((this.TotalItemCount != -1) && (this.PageSize > 0)) && this.MoveToPage(this.PageCount - 1));
            return a;
        }

        /// <summary>
        ///  总页数
        /// </summary>
        private int PageCount
        {
            get
            {
                if (this.PageSize <= 0)
                {
                    return 0;
                }

                return Math.Max(1, (int)Math.Ceiling(((double)this.TotalItemCount) / ((double)this.PageSize)));
            }
        }

        public bool MoveToNextPage()
        {
            return this.MoveToPage(this.PageIndex + 1);
        }

        public bool MoveToPage(int pageIndex)
        {
            if (pageIndex < 0 || pageIndex >= this.PageCount)
            {
                this.RaisePropertyChanged("PageCount");
                this.RaisePropertyChanged("PageIndex");
                return false;
            }

            if (this.RaisePageChanging(this.PageIndex))
            {
                return false;
            }

            this.PageIndex = pageIndex;
            this.Refresh();
            this.RaisePropertyChanged("PageCount");
            this.RaisePageChanged();
            return true;
        }

        public bool MoveToPreviousPage()
        {
            return this.MoveToPage(this.PageIndex - 1);
        }

        /// <summary>
        /// 0 开始
        /// </summary>
        public int PageIndex
        {
            get
            {
                return this._pageIndex;
            }

            private set
            {
                this._pageIndex = value;
                this.RaisePropertyChanged("PageIndex");
            }
        }

        public int PageSize
        {
            get
            {
                return this._pageSize;
            }

            set
            {
                this._pageSize = value;
                this.RaisePropertyChanged("PageSize");
                this.RaisePropertyChanged("PageCount");
            }
        }

        public int TotalItemCount
        {
            get
            {
                return this._totalItemCount;
            }

            private set
            {
                this._totalItemCount = value;
                this.RaisePropertyChanged("TotalItemCount");
            }
        }
        #endregion

        #region INotifyPropertyChanged

        protected void RaisePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion

        private void RaisePageChanged()
        {
            if (this.PageChanged != null)
            {
                this.PageChanged(this, EventArgs.Empty);
            }
        }

        private bool RaisePageChanging(int newPageIndex)
        {
            if (this.PageChanging != null)
            {
                PageChangingEventArgs e = new PageChangingEventArgs(newPageIndex);
                this.PageChanging(this, e);
                return e.Cancel;
            }

            return false;
        }

        public int IndexOf(object obj)
        {
            int index = -1;

            int i = 0;
            foreach (var o in this)
            {
                if (o == obj)
                {
                    index = i;
                    this.CurrentItem = o;
                    break;
                }

                i++;
            }

            return index;
        }

        private void SetCurrentToPosition(int position)
        {
            if (position < 0)
            {
                this.SetFlag(CollectionViewFlags.IsCurrentBeforeFirst, true);
                this.SetCurrent(null, -1);
            }
            else if (position >= this.Count)
            {
                this.SetFlag(CollectionViewFlags.IsCurrentAfterLast, true);
                this.SetCurrent(null, this.Count);
            }
            else
            {
                this.SetFlag(CollectionViewFlags.IsCurrentAfterLast | CollectionViewFlags.IsCurrentBeforeFirst, false);
                this.SetCurrent(this.GetItemAt(position), position);
            }
        }

        private void SetCurrent(object newItem, int newPosition)
        {
            int count = (newItem != null) ? 0 : (this.IsEmpty ? 0 : this.Count);
            this.SetCurrent(newItem, newPosition, count);
        }

        private void SetCurrent(object newItem, int newPosition, int count)
        {
            if (newItem != null)
            {
                this.SetFlag(CollectionViewFlags.IsCurrentBeforeFirst, false);
                this.SetFlag(CollectionViewFlags.IsCurrentAfterLast, false);
            }
            else if (count == 0)
            {
                this.SetFlag(CollectionViewFlags.IsCurrentBeforeFirst, true);
                this.SetFlag(CollectionViewFlags.IsCurrentAfterLast, true);
                newPosition = -1;
            }
            else
            {
                this.SetFlag(CollectionViewFlags.IsCurrentBeforeFirst, newPosition < 0);
                this.SetFlag(CollectionViewFlags.IsCurrentAfterLast, newPosition >= count);
            }

            this.CurrentItem = newItem;
            this.CurrentPosition = newPosition;
        }

        public object GetItemAt(int index)
        {
            return this.internalSourceCollection[index];
        }

        private void SetFlag(CollectionViewFlags flags, bool value)
        {
            if (value)
            {
                this._flags |= flags;
            }
            else
            {
                this._flags &= ~flags;
            }
        }

        private void OnCurrentChanged()
        {
            if (this.CurrentChanged != null)
            {
                this.CurrentChanged(this, EventArgs.Empty);
            }
        }

        private void OnCollectionChanged()
        {
            if (this.CollectionChanged != null)
            {
                this.CollectionChanged(this, new System.Collections.Specialized.NotifyCollectionChangedEventArgs(System.Collections.Specialized.NotifyCollectionChangedAction.Reset));
            }
        }

        public int Count
        {
            get
            {
                return this.internalSourceCollection.Count;
            }
        }

        private class DeferHelper : IDisposable
        {
            // Fields
            private DynamicDataCollectionView collectionView;

            // Methods
            public DeferHelper(DynamicDataCollectionView collectionView)
            {
                this.collectionView = collectionView;
            }

            public void Dispose()
            {
                if (this.collectionView != null)
                {
                    this.collectionView.Refresh();
                    this.collectionView = null;
                }

                GC.SuppressFinalize(this);
            }
        }

        [Flags]
        private enum CollectionViewFlags
        {
            CachedIsEmpty = 0x40,
            IsCurrentAfterLast = 0x10,
            IsCurrentBeforeFirst = 8,
            IsDataInGroupOrder = 1,
            IsDataSorted = 2,
            IsMoveToPageDeferred = 0x100,
            IsPageChanging = 0x80,
            IsUpdatePageSizeDeferred = 0x200,
            NeedsRefresh = 0x20,
            ShouldProcessCollectionChanged = 4
        }
    }
}
